<template>
  <div class="ansible-playbooks">
    <div class="page-header">
      <h2>🏕️ Playbook编辑执行</h2>
      <p class="subtitle">在线编辑和执行Ansible Playbook</p>
    </div>

    <!-- 操作栏 -->
    <div class="action-bar">
      <div class="tabs">
        <button 
          class="tab-btn" 
          :class="{ active: currentTab === 'edit' }"
          @click="currentTab = 'edit'"
        >
          📝 在线编辑
        </button>
        <button 
          class="tab-btn" 
          :class="{ active: currentTab === 'upload' }"
          @click="currentTab = 'upload'"
        >
          📂 选择现有
        </button>
      </div>
      <button class="btn btn-primary" @click="showPlaybookList = true">
        📋 Playbook列表
      </button>
    </div>

    <!-- 主内容区 -->
    <div class="content-container">
      <!-- 左侧编辑器 -->
      <div class="editor-panel">
        <div class="panel-header">
          <div class="config-row">
            <label>Ansible配置:</label>
            <select v-model="selectedAnsibleHost" class="select-input">
              <option value="">选择Ansible控制节点</option>
              <option v-for="host in hosts" :key="host.id" :value="host.ip">
                {{ host.ip }} ({{ host.name }})
              </option>
            </select>
          </div>
          
          <div class="config-row">
            <label>目标主机:</label>
            <select v-model="selectedTargetHost" class="select-input">
              <option value="">选择目标主机</option>
              <option v-for="host in hosts" :key="host.id" :value="host.ip">
                {{ host.ip }} ({{ host.name }})
              </option>
            </select>
          </div>
          
          <div class="config-row">
            <label>主机清单:</label>
            <select v-model="selectedInventory" class="select-input">
              <option value="">选择主机清单</option>
              <option v-for="inv in inventories" :key="inv.id" :value="inv.id">
                {{ inv.name }} ({{ inv.host_count }}台主机)
              </option>
            </select>
          </div>
          
          <div class="config-row">
            <label>执行凭据:</label>
            <select v-model="selectedCredential" class="select-input">
              <option value="">选择凭据</option>
              <option v-for="cred in credentials" :key="cred.id" :value="cred.id">
                {{ cred.name }} ({{ getCredTypeText(cred.credential_type) }})
              </option>
            </select>
          </div>
        </div>

        <div class="editor-toolbar">
          <input 
            v-model="playbookName" 
            placeholder="playbook.yml" 
            class="playbook-name-input"
          />
          <label class="btn btn-sm btn-upload">
            📁 上传文件
            <input type="file" accept=".yml,.yaml" @change="handleFileUpload" style="display: none" />
          </label>
          <button class="btn btn-sm btn-success" @click="executePlaybook" :disabled="isExecuting">
            {{ isExecuting ? '⏳ 执行中...' : '▶️ 执行' }}
          </button>
          <button class="btn btn-sm btn-info" @click="syntaxCheck">
            ✓ 语法检查
          </button>
          <button class="btn btn-sm" @click="savePlaybook">
            💾 保存
          </button>
          <button class="btn btn-sm" @click="downloadPlaybook">
            ⬇️ 下载
          </button>
        </div>

        <!-- YAML编辑器 -->
        <div class="code-editor-wrapper">
          <textarea 
            v-model="playbookContent" 
            class="code-editor"
            spellcheck="false"
            @keydown.tab.prevent="handleTab"
          ></textarea>
          <div class="line-numbers">
            <div v-for="n in lineCount" :key="n" class="line-number">{{ n }}</div>
          </div>
        </div>
      </div>

      <!-- 右侧执行结果 -->
      <div class="result-panel">
        <div class="result-header">
          <span class="result-title">📊 执行结果</span>
          <div class="result-actions">
            <button class="btn btn-sm" @click="clearResult">🗑️ 清空</button>
            <button class="btn btn-sm btn-primary" @click="copyResult">📋 复制</button>
            <button class="btn btn-sm" @click="downloadResult">⬇️ 下载</button>
          </div>
        </div>
        
        <div class="result-content" ref="resultContent">
          <div v-if="!currentResult" class="result-empty">
            <div class="empty-icon">🏕️</div>
            <p>等待执行Playbook...</p>
            <small>点击"执行"按钮开始运行</small>
          </div>
          
          <div v-else class="result-output">
            <div v-if="currentResult.status === 'running'" class="status-badge status-running">
              ⏳ 运行中...
            </div>
            <div v-else-if="currentResult.status === 'success'" class="status-badge status-success">
              ✅ 执行成功
            </div>
            <div v-else-if="currentResult.status === 'failed'" class="status-badge status-failed">
              ❌ 执行失败
            </div>
            
            <div class="result-stats" v-if="currentResult.result">
              <div class="stat-item">
                <span class="stat-label">耗时:</span>
                <span class="stat-value">{{ currentResult.duration || 'N/A' }}</span>
              </div>
              <div class="stat-item">
                <span class="stat-label">主机:</span>
                <span class="stat-value">{{ currentResult.inventory_name }}</span>
              </div>
            </div>
            
            <div class="output-section">
              <h4>📤 标准输出</h4>
              <pre class="output-text">{{ currentResult.stdout || '无输出' }}</pre>
            </div>
            
            <div v-if="currentResult.stderr" class="output-section error">
              <h4>⚠️ 错误输出</h4>
              <pre class="output-text">{{ currentResult.stderr }}</pre>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- Playbook列表弹窗 -->
    <div v-if="showPlaybookList" class="modal-overlay" @click="showPlaybookList = false">
      <div class="modal-content" @click.stop>
        <div class="modal-header">
          <h3>📋 Playbook列表</h3>
          <button class="btn-close" @click="showPlaybookList = false">✕</button>
        </div>
        <div class="modal-body">
          <div class="playbook-list">
            <div 
              v-for="pb in playbooks" 
              :key="pb.id" 
              class="playbook-item"
              @click="loadPlaybook(pb)"
            >
              <div class="playbook-info">
                <div class="playbook-title">{{ pb.name }}</div>
                <div class="playbook-meta">
                  创建者: {{ pb.created_by_name }} | {{ formatDate(pb.created_at) }}
                </div>
              </div>
              <div class="playbook-actions">
                <button class="btn btn-sm btn-danger" @click.stop="deletePlaybook(pb.id)">
                  删除
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import api from '../services/api'

// 数据
const currentTab = ref('edit')
const playbookName = ref('playbook.yml')
const playbookContent = ref(`---
- name: 示例Playbook
  hosts: all
  become: yes
  
  vars:
    app_name: "my-app"
  
  tasks:
    - name: 测试连接
      ping:
    
    - name: 输出信息
      debug:
        msg: "Hello from {{ inventory_hostname }}"
`)

const hosts = ref([])
const inventories = ref([])
const credentials = ref([])
const playbooks = ref([])
const selectedAnsibleHost = ref('')
const selectedTargetHost = ref('')
const selectedInventory = ref('')
const selectedCredential = ref('')
const currentResult = ref(null)
const isExecuting = ref(false)
const showPlaybookList = ref(false)

// 计算属性
const lineCount = computed(() => {
  return playbookContent.value.split('\n').length
})

// 方法
const loadData = async () => {
  try {
    const [hostData, invData, credData, pbData] = await Promise.all([
      api.getHosts(),
      api.getInventories(),
      api.getCredentials(),
      api.getPlaybooks()
    ])
    hosts.value = hostData.results || hostData
    inventories.value = invData
    credentials.value = credData
    playbooks.value = pbData
  } catch (error) {
    console.error('加载数据失败:', error)
    alert('加载数据失败')
  }
}

const getCredTypeText = (type) => {
  const map = {
    'ssh_password': '🔐密码',
    'ssh_key': '🔑密钥',
    'vault': '🔒Vault'
  }
  return map[type] || type
}

const handleFileUpload = (event) => {
  const file = event.target.files[0]
  if (!file) return
  
  if (!file.name.endsWith('.yml') && !file.name.endsWith('.yaml')) {
    alert('请选择.yml或.yaml文件')
    return
  }
  
  const reader = new FileReader()
  reader.onload = (e) => {
    playbookContent.value = e.target.result
    playbookName.value = file.name
    console.log('文件上传成功:', file.name)
  }
  reader.onerror = () => {
    console.error('文件读取失败')
  }
  reader.readAsText(file)
  
  // 重置input，允许重复上传同一文件
  event.target.value = ''
}

const handleTab = (e) => {
  const start = e.target.selectionStart
  const end = e.target.selectionEnd
  playbookContent.value = playbookContent.value.substring(0, start) + '  ' + playbookContent.value.substring(end)
  e.target.selectionStart = e.target.selectionEnd = start + 2
}

const syntaxCheck = async () => {
  try {
    const result = await api.syntaxCheck({ content: playbookContent.value })
    if (result.valid) {
      console.log('✅ 语法检查通过')
    } else {
      console.error('语法错误:', result.message)
    }
  } catch (error) {
    console.error('语法检查失败:', error.response?.data?.error || error.message)
  }
}

const savePlaybook = async () => {
  if (!playbookName.value) {
    alert('请输入Playbook名称')
    return
  }
  
  try {
    const data = {
      name: playbookName.value,
      content: playbookContent.value,
      inventory: selectedInventory.value || null,
      credential: selectedCredential.value || null,
      status: 'active'
    }
    
    await api.createPlaybook(data)
    console.log('Playbook保存成功')
    loadData()
  } catch (error) {
    console.error('保存失败:', error.response?.data?.error || error.message)
  }
}

const executePlaybook = async () => {
  if (!selectedInventory.value || !selectedCredential.value) {
    alert('请选择主机清单和凭据')
    return
  }
  
  isExecuting.value = true
  currentResult.value = { status: 'running' }
  
  try {
    // 先保存
    const playbook = await api.createPlaybook({
      name: playbookName.value || 'temp_' + Date.now(),
      content: playbookContent.value,
      status: 'draft'
    })
    
    // 执行
    const result = await api.executePlaybook(playbook.id, {
      inventory_id: selectedInventory.value,
      credential_id: selectedCredential.value
    })
    
    currentResult.value = result
    console.log('执行完成:', result.status)
  } catch (error) {
    currentResult.value = {
      status: 'failed',
      stderr: error.response?.data?.error || error.message
    }
    console.error('执行失败:', error.response?.data?.error || error.message)
  } finally {
    isExecuting.value = false
  }
}

const loadPlaybook = (playbook) => {
  playbookName.value = playbook.name
  playbookContent.value = playbook.content
  if (playbook.inventory) selectedInventory.value = playbook.inventory
  if (playbook.credential) selectedCredential.value = playbook.credential
  showPlaybookList.value = false
}

const deletePlaybook = async (id) => {
  if (!confirm('确定要删除这个Playbook吗？')) return
  
  try {
    await api.deletePlaybook(id)
    console.log('删除成功')
    loadData()
  } catch (error) {
    console.error('删除失败:', error.response?.data?.error || error.message)
  }
}

const downloadPlaybook = () => {
  const blob = new Blob([playbookContent.value], { type: 'text/yaml' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = playbookName.value || 'playbook.yml'
  a.click()
  URL.revokeObjectURL(url)
}

const clearResult = () => {
  currentResult.value = null
}

const copyResult = () => {
  const text = currentResult.value?.stdout || ''
  navigator.clipboard.writeText(text)
  console.log('已复制到剪贴板')
}

const downloadResult = () => {
  const text = currentResult.value?.stdout || ''
  const blob = new Blob([text], { type: 'text/plain' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = 'result.txt'
  a.click()
  URL.revokeObjectURL(url)
}

const formatDate = (dateString) => {
  return new Date(dateString).toLocaleString('zh-CN')
}

onMounted(() => {
  loadData()
})
</script>

<style scoped>
.ansible-playbooks {
  padding: 20px;
}

.page-header {
  margin-bottom: 20px;
}

.page-header h2 {
  font-size: 28px;
  margin: 0 0 8px 0;
  color: #FFB6C1;
}

.subtitle {
  color: rgba(255, 255, 255, 0.6);
  margin: 0;
  font-size: 14px;
}

.action-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
  padding: 15px;
  background: rgba(255, 182, 193, 0.1);
  border-radius: 8px;
  border: 1px solid rgba(255, 182, 193, 0.3);
}

.tabs {
  display: flex;
  gap: 10px;
}

.tab-btn {
  padding: 10px 20px;
  background: transparent;
  border: 2px solid rgba(255, 182, 193, 0.3);
  color: rgba(255, 255, 255, 0.7);
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
  font-size: 14px;
}

.tab-btn:hover {
  border-color: rgba(255, 182, 193, 0.6);
  background: rgba(255, 182, 193, 0.1);
}

.tab-btn.active {
  background: linear-gradient(135deg, rgba(255, 182, 193, 0.3), rgba(135, 206, 250, 0.2));
  border-color: #FFB6C1;
  color: #FFB6C1;
}

.content-container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
  height: calc(100vh - 280px);
}

.editor-panel,
.result-panel {
  background: rgba(30, 40, 55, 0.8);
  border-radius: 8px;
  border: 2px solid rgba(255, 182, 193, 0.2);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.panel-header {
  padding: 15px;
  background: rgba(255, 182, 193, 0.1);
  border-bottom: 1px solid rgba(255, 182, 193, 0.2);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.config-row {
  display: flex;
  align-items: center;
  gap: 15px;
}

.config-row label {
  color: #FFB6C1;
  font-size: 14px;
  font-weight: 600;
  min-width: 100px;
  white-space: nowrap;
}

.select-input {
  flex: 1;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 182, 193, 0.3);
  border-radius: 4px;
  color: #fff;
  font-size: 13px;
}

.editor-toolbar {
  display: flex;
  gap: 10px;
  padding: 12px 15px;
  background: rgba(0, 0, 0, 0.2);
  border-bottom: 1px solid rgba(255, 182, 193, 0.2);
  align-items: center;
}

.playbook-name-input {
  flex: 1;
  padding: 8px 12px;
  background: rgba(0, 0, 0, 0.3);
  border: 1px solid rgba(255, 182, 193, 0.3);
  border-radius: 4px;
  color: #FFB6C1;
  font-size: 14px;
  font-weight: 600;
}

.code-editor-wrapper {
  flex: 1;
  position: relative;
  overflow: auto;
  background: #0a0e1a;
}

.line-numbers {
  position: absolute;
  left: 0;
  top: 0;
  width: 50px;
  background: rgba(0, 0, 0, 0.3);
  border-right: 1px solid rgba(255, 182, 193, 0.2);
  user-select: none;
  padding: 15px 0;
}

.line-number {
  text-align: right;
  padding-right: 10px;
  color: rgba(255, 255, 255, 0.3);
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 13px;
  line-height: 1.6;
  height: 21px;
}

.code-editor {
  width: 100%;
  height: 100%;
  padding: 15px 15px 15px 60px;
  background: transparent;
  border: none;
  color: #87CEEB;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 14px;
  line-height: 1.6;
  resize: none;
  outline: none;
  tab-size: 2;
}

.result-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px;
  background: rgba(255, 182, 193, 0.1);
  border-bottom: 1px solid rgba(255, 182, 193, 0.2);
}

.result-title {
  color: #FFB6C1;
  font-size: 16px;
  font-weight: 600;
}

.result-actions {
  display: flex;
  gap: 8px;
}

.result-content {
  flex: 1;
  overflow: auto;
  padding: 20px;
}

.result-empty {
  text-align: center;
  padding: 60px 20px;
  color: rgba(255, 255, 255, 0.5);
}

.empty-icon {
  font-size: 64px;
  margin-bottom: 15px;
}

.status-badge {
  display: inline-block;
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 15px;
}

.status-running {
  background: rgba(255, 184, 0, 0.2);
  color: #FFB800;
  border: 1px solid #FFB800;
}

.status-success {
  background: rgba(0, 255, 200, 0.2);
  color: #00FFC8;
  border: 1px solid #00FFC8;
}

.status-failed {
  background: rgba(255, 70, 85, 0.2);
  color: #FF4655;
  border: 1px solid #FF4655;
}

.result-stats {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
  padding: 15px;
  background: rgba(0, 0, 0, 0.2);
  border-radius: 6px;
}

.stat-item {
  display: flex;
  gap: 8px;
}

.stat-label {
  color: rgba(255, 255, 255, 0.6);
}

.stat-value {
  color: #FFB6C1;
  font-weight: 600;
}

.output-section {
  margin-bottom: 20px;
}

.output-section h4 {
  color: #FFB6C1;
  margin-bottom: 10px;
  font-size: 14px;
}

.output-text {
  background: #0a0e1a;
  padding: 15px;
  border-radius: 6px;
  border: 1px solid rgba(255, 182, 193, 0.2);
  color: #87CEEB;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 13px;
  line-height: 1.6;
  overflow-x: auto;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.output-section.error .output-text {
  color: #FF4655;
  border-color: rgba(255, 70, 85, 0.3);
}

/* 按钮样式 */
.btn {
  padding: 8px 16px;
  border-radius: 6px;
  border: none;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  transition: all 0.3s;
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(255, 182, 193, 0.3);
}

.btn-primary {
  background: linear-gradient(135deg, #FFB6C1, #87CEEB);
  border: none;
}

.btn-success {
  background: linear-gradient(135deg, #00FFC8, #4CAF50);
  border: none;
}

.btn-info {
  background: linear-gradient(135deg, #87CEEB, #4D94FF);
  border: none;
}

.btn-danger {
  background: linear-gradient(135deg, #FF4655, #FF6B7A);
  border: none;
}

.btn-upload {
  background: linear-gradient(135deg, #FFD700, #FFA500);
  border: none;
  cursor: pointer;
}

.btn-upload:hover {
  transform: translateY(-2px);
}

.btn-sm {
  padding: 6px 12px;
  font-size: 12px;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* 弹窗样式 */
.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}

.modal-content {
  background: rgba(30, 40, 55, 0.95);
  border-radius: 12px;
  border: 2px solid rgba(255, 182, 193, 0.3);
  width: 90%;
  max-width: 800px;
  max-height: 80vh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.modal-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 20px;
  background: rgba(255, 182, 193, 0.1);
  border-bottom: 1px solid rgba(255, 182, 193, 0.2);
}

.modal-header h3 {
  margin: 0;
  color: #FFB6C1;
  font-size: 20px;
}

.btn-close {
  background: none;
  border: none;
  color: #fff;
  font-size: 24px;
  cursor: pointer;
  padding: 0;
  width: 32px;
  height: 32px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  transition: all 0.3s;
}

.btn-close:hover {
  background: rgba(255, 70, 85, 0.2);
}

.modal-body {
  flex: 1;
  overflow: auto;
  padding: 20px;
}

.playbook-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.playbook-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 15px;
  background: rgba(0, 0, 0, 0.2);
  border: 1px solid rgba(255, 182, 193, 0.2);
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.3s;
}

.playbook-item:hover {
  background: rgba(255, 182, 193, 0.1);
  border-color: rgba(255, 182, 193, 0.4);
  transform: translateX(5px);
}

.playbook-title {
  color: #FFB6C1;
  font-weight: 600;
  margin-bottom: 5px;
}

.playbook-meta {
  color: rgba(255, 255, 255, 0.5);
  font-size: 12px;
}
</style>
